package finalproject.mobapp.Main;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import finalproject.mobapp.R;
import finalproject.mobapp.ARPackage.ARObject;
import finalproject.mobapp.ARPackage.ARView;
import finalproject.mobapp.ARPackage.Poi;
import finalproject.mobapp.ARPackage.PoiRetrieval;
import finalproject.mobapp.HttpRequestController.CustomHttpClient;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;

public class ARViewActivity extends Activity implements SensorEventListener, SurfaceHolder.Callback {
	
	Context context = this;
	
	Camera camera;
	SurfaceView surfaceView;
	SurfaceHolder surfaceHolder;
	boolean previewing = false;
	
	LocationManager locationManager;
	Location gps_loc;
	Location net_loc;
	boolean gps_enabled = false;
	boolean network_enabled = false;
	
	SensorManager sensorManager;
	float alpha;
	float pitch = -90;
	
	Bundle extras;
	String category;
	int radius = 0;
	Location myLocation;
	
	ARView myARView;
	HashMap<Integer, Poi> nearbyPois;
	HashMap<Integer, Float> poiTethas;
	HashMap<Integer, Float[]> poiPositions;
	
	static final private int MENU_MAPVIEW = Menu.FIRST;
	static final private int MENU_LISTVIEW = Menu.FIRST+1;
	
	/** Called when the activity is first created. */	
	@Override
    public void onCreate(Bundle savedInstanceState) {
    	super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_arview);
        
        //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        
        getWindow().setFormat(PixelFormat.UNKNOWN);
        surfaceView = (SurfaceView) findViewById(R.id.camerapreview);
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        
        myARView = new ARView(getApplicationContext(), this);
        
        LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
        this.addContentView(myARView, layoutParams);
        
        //myARView = (ARView) findViewById(R.id.myarview);
        locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
        
        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
        
        nearbyPois = new HashMap<Integer, Poi>();
        
        gps_enabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
        network_enabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
        
        getLocation();
        
        extras = getIntent().getExtras();
        if (extras != null) {
        	category = extras.getString("category");
        	radius = extras.getInt("radius");
        	
        	if (myLocation != null) {
        		updateNearbyPoiList();
        		updatePoiTethas();
        		updatePoiPositions();
        		updateARView();
        	}
        }
    }
	
	@Override
	public void onStop() {
		locationManager.removeUpdates(gpsListener);
		locationManager.removeUpdates(networkListener);
		super.onStop();
	}
	
	public void getLocation() {
		if (gps_enabled) {
        	gps_loc = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        	if (gps_loc != null) {
				myLocation = gps_loc;
			}
        }
        
        if (network_enabled) {
        	net_loc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        	if (net_loc != null) {
				if (gps_loc == null) {
					myLocation = net_loc;
				}
			}
        }
        
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, gpsListener);
        locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, networkListener);
	}
	
	public void updateNearbyPoiList() {
		nearbyPois = PoiRetrieval.GetNearbyPois(category, radius, myLocation);
	}
	
	public void updatePoiTethas() {
		poiTethas = new HashMap<Integer, Float>();
		
		if (nearbyPois.size() > 0) {
			Iterator<Integer> e = nearbyPois.keySet().iterator();
			do {
				int poi_id = e.next();
				Poi poi = nearbyPois.get(poi_id);
				Location poi_location = poi.getLocation();
				
				float tetha = myLocation.bearingTo(poi_location);
				if (tetha < 0) {
	        		tetha += 360;
	        	}
				poiTethas.put(poi_id, tetha);				
			} while (e.hasNext());
		}
	}
	
	public void updatePoiPositions() {
		poiPositions = new HashMap<Integer, Float[]>();
		
		if (poiTethas.size() > 0) {
			Iterator<Integer> e = nearbyPois.keySet().iterator();
			do {
				int poi_id = e.next();
				//Poi poi = nearbyPois.get(poi_id);
				//String poi_title = poi.getTitle();
				float tetha = poiTethas.get(poi_id);
				
				float betha = tetha - alpha;
				Float[] values = {betha, pitch};
				poiPositions.put(poi_id, values);
			} while (e.hasNext());
		}
	}
	
	public void updateARView() {
		if (poiPositions.size() > 0) {
			myARView.setMyLocation(myLocation);
			myARView.setNearbyPois(nearbyPois);
			myARView.updateLayout(poiPositions);
		}
	}
	
	public void takeMeThere(int poi_id) {
		Poi poi = nearbyPois.get(poi_id);
		Location poiLocation = poi.getLocation();
		Intent intent = new Intent();
		intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");
    	intent.setAction(Intent.ACTION_VIEW);
    	String uri = "http://maps.google.com/maps?saddr="+String.valueOf(myLocation.getLatitude())+","+String.valueOf(myLocation.getLongitude())+"&daddr="+String.valueOf(poiLocation.getLatitude())+","+String.valueOf(poiLocation.getLongitude());
    	intent.setData(Uri.parse(uri));
    	startActivity(intent);
	}
	
	public void viewInfo(int poi_id) {
		Poi poi = nearbyPois.get(poi_id);
		String title = poi.getTitle();
		String description = poi.getDescription();
		float distance = poi.getDistance();
		
		Intent intent = new Intent();
		intent.setClass(getApplicationContext(), InfoViewActivity.class);
		intent.putExtra("title", title);
		intent.putExtra("description", description);
		intent.putExtra("distance", distance);
		startActivity(intent);
	}
	
	public void ARObjectHandle(int poi_id, int object_id) {
		Poi poi = nearbyPois.get(poi_id);
		ArrayList<ARObject> objects = poi.getObjects();
		ARObject object = null;
		boolean found = false;
		
		int i = 0;
		while (i<objects.size() && !found) {
			object = objects.get(i);
			if (object.getId() == object_id) {
				found = true;
			} else {
				i++;
			}
		}
		
		if (found) {
			String path = object.getPath();
			String uri = CustomHttpClient.RES_URL + String.valueOf(poi_id) + "/" + path;
			
			Intent intent = new Intent();
			int type = object.getType();
			if (type == 1) {
				//image type
				intent.setClass(getApplicationContext(), ImageShowActivity.class);
				intent.putExtra("uri", uri);
				startActivity(intent);
			} else if (type == 2) {
				//video type
				intent.setClass(getApplicationContext(), VideoPlayActivity.class);
				intent.putExtra("uri", uri);
				startActivity(intent);
			}
		}
	}
	
	LocationListener gpsListener = new LocationListener() {
		
		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onLocationChanged(Location location) {
			// TODO Auto-generated method stub
			gps_loc = location;
			if (gps_loc != null) {
				myLocation = gps_loc;
				updateNearbyPoiList();
        		updatePoiTethas();
        		updatePoiPositions();
        		updateARView();
			}
		}
	};
	
	LocationListener networkListener = new LocationListener() {
		
		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void onLocationChanged(Location location) {
			// TODO Auto-generated method stub
			net_loc = location;
			if (net_loc != null) {
				myLocation = net_loc;
				updateNearbyPoiList();
        		updatePoiTethas();
        		updatePoiPositions();
        		updateARView();
			}
		}
	};
	
	@Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	super.onCreateOptionsMenu(menu);
        menu.add(0, MENU_MAPVIEW, Menu.NONE, "Map View");
        menu.add(0, MENU_LISTVIEW, Menu.NONE, "List View");
        return true;
    }
	
	@Override
    public boolean onOptionsItemSelected(MenuItem item) {
		super.onOptionsItemSelected(item);
		
		Intent intent = new Intent();
		
		switch (item.getItemId()) {
		case (MENU_MAPVIEW):
			// Start the MapViewActivity
    		intent.setClass(context, MapViewActivity.class);
    		intent.putExtra("category", category);
    		intent.putExtra("radius", radius);
    		
    		ARViewActivity.this.finish();
    		startActivity(intent);
        	return true;
		
		case (MENU_LISTVIEW):
			// Start the ARListViewActivity
    		intent.setClass(context, ARListViewActivity.class);
    		intent.putExtra("category", category);
    		intent.putExtra("radius", radius);
    		
    		ARViewActivity.this.finish();
    		startActivity(intent);
        	return true;
	
		default:
			break;
		}
		
		// Return false if you have not handled the menu item.
		return false;
    }

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onSensorChanged(SensorEvent event) {
		// TODO Auto-generated method stub
		if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
			alpha = event.values[0];
			pitch = event.values[1];
			updatePoiPositions();
			updateARView();
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		if (previewing) {
			camera.stopPreview();
			previewing = false;
		}
		
		if (camera != null) {
			try {
				camera.setPreviewDisplay(surfaceHolder);
				camera.startPreview();
				previewing = true;
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		camera = Camera.open();
		camera.setDisplayOrientation(90);
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		camera.stopPreview();
		camera.release();
		camera = null;
		previewing = false;
	}	
}
